package edu.pku.sei.autounit.generator;

import java.util.ArrayList;
import java.util.Collection;
import java.util.Map;

import edu.pku.sei.autounit.core.Variable;
import edu.pku.sei.autounit.core.VariableFactory;
import edu.pku.sei.autounit.core.VariableGenerator;
import edu.pku.sei.autounit.filter.Filter;
import edu.pku.sei.autounit.reflect.Context;
import edu.pku.sei.autounit.reflect.Type;
import edu.pku.sei.autounit.reflect.java.JavaClass;
import edu.pku.sei.autounit.reflect.java.JavaInterface;
import edu.pku.sei.autounit.reflect.java.TypeFactory;
import edu.pku.sei.autounit.util.NameFactory;
import edu.pku.sei.autounit.util.Properties;
import edu.pku.sei.autounit.util.Statements;

public class CollectionGenerator implements VariableGenerator{

	public Variable generate(Type type, String name, VariableFactory vf,
			NameFactory nf) {
		
		if(type instanceof Context){
			TypeFactory tf = new TypeFactory();
			
			Type list = new JavaClass(ArrayList.class,((Context) type).getContexts(),tf);
			if(type.isAssignableFrom(list)){
				Variable v = null;
				if(type.equals(list))
					v = vf.getVariableContinue(list, name, nf, this);
				else
					v = vf.getVariableContinue(list, nf.getName("ArrayList", NameFactory.TEMP), nf, this);
				return new CollectionVariable(type,name,v,vf,nf);
			}
			
			if(((Context) type).getContexts().length!=1)
				return null;
			Type collection = new JavaInterface(Collection.class,((Context) type).getContexts(),tf);
			
			if(collection.isAssignableFrom(type)){
				Variable v = vf.getVariableContinue(type,name, nf, this);
				return new CollectionVariable(type,name,v,vf,nf);
			}
		}
		return null;
	}

	public Variable generate(Type type, String name, Filter fliter,
			VariableFactory vf, NameFactory nf) {
		// TODO Auto-generated method stub
		return null;
	}
	
	static class CollectionVariable implements Variable{

		private Collection<Variable> list;
		private Type type;
		private Variable variable;
		private String name;
		
		public CollectionVariable(Type type,String name ,Variable variable,VariableFactory vf,NameFactory nf) {
			this.variable = variable;
			this.type = type;
			this.name = name;
			list = new ArrayList<Variable>();
			int size = Properties.getCollectionSize();
			Type [] contexts = ((Context) type).getContexts();
			if(contexts.length==1){
				for(int i = 0 ;i<size;i++){
					Variable e = vf.getVariable(contexts[0], 
							nf.getName(contexts[0].getFullName(), NameFactory.ELEMENT), vf, nf);
					list.add(e);
				}
			}
		}

		public Statements getInitCode(Map<String,String> map){
			
			Statements s =new Statements();

			s.merge(variable.getInitCode(map));
			if(!variable.getValue().equals(name))
				s.insertStatement(type.getName(map)+" "+name+" = "+variable.getValue()+";");
			
			for(Variable e:list){
				s.merge(e.getInitCode(map));
			}
			
			for(Variable e:list){
				StringBuffer sb = new StringBuffer();
				sb.append(name);
				sb.append(".add(");
				sb.append(e.getValue());
				sb.append(");");
				s.insertStatement(sb.toString());
			}
			return s;
		}

		public String getValue() {
			return name;
		}

		public Type getType() {
			return type;
		}
	}

}
